package com.biodiv.miracle.ioc.processor;

import com.biodiv.miracle.support.annotation.Autowired;
import com.biodiv.miracle.support.annotation.Qualifier;
import com.biodiv.miracle.support.utils.MiracleUtils;

import java.lang.reflect.Field;

/**
 * @Author: tianquan
 * @date: 2024-09-30  09:18
 * @Description: 解析@Autowired注解，自动注入bean
 */
public class AutowiredBeanPostProcessor implements InjectBeanPostProcessor {

    /**
     * 自动注入逻辑
     * 遍历指定bean的所有字段，寻找带有@Autowired注解的字段，并尝试注入相应的Bean
     *
     * @param bean 要进行自动注入的Bean对象
     */
    @Override
    public void inject(Object bean) {
        // 获取当前bean的类信息
        Class<?> aClass = bean.getClass();
        // 遍历所有字段
        for (Field field : aClass.getDeclaredFields()) {
            // 检查字段上是否有@Autowired注解
            Autowired autowired = field.getAnnotation(Autowired.class);
            if (autowired == null) {
                continue;
            }
            // 同spirng一样用暴力反射
            field.setAccessible(true);
            try {
                // 优先根据类型注入
                Class<?> fieldClass = field.getType();
                Object value = MiracleUtils.getBean(fieldClass);
                if (value == null) {
                    // 判断是否有Qualifier注解
                    Qualifier qualifier = field.getAnnotation(Qualifier.class);
                    if (qualifier == null) {
                        throw new RuntimeException("can not find bean is " + field.getName());
                    }
                    String beanName = MiracleUtils.createBeanName(fieldClass);
                    value = MiracleUtils.getBean(beanName);
                    // 判断是否必须
                    if (autowired.required() && value == null) {
                        throw new RuntimeException("can not find bean is " + field.getName());
                    }
                }
                // 注入
                field.set(bean, value);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }

}

